/**
 * @author : andy
 * @description : 请求功能
 */
import axios, { type AxiosError, type AxiosRequestConfig, type AxiosResponse , type InternalAxiosRequestConfig } from 'axios';
import type Result from '../types/result';
import Auth from '@/services/auth';
// 请求配置类型
interface AxiosRequestOptions extends InternalAxiosRequestConfig {
  // 是否取消重复请求
  repeatRequestCancel?: boolean;
  // 是否需要保存canceltoken，主要目的是为了让开发者可以手动取消请求
  saveCancelToken?: boolean;
}
// 相应配置类型
interface AxiosResponseOptions extends AxiosResponse {
  config : AxiosRequestOptions;
}
// 导出，用于手动取消请求
export const requestCancelUtil = {
  // 用于保存cancelToken，格式：{cancelTokenKey : cancelToken}
  cancel : new Map(),
  /**
   * 添加取消重复请求的cancelToken
   * @param {AxiosRequestOptions} config 请求配置对象
   */
  addCancelRequest (config: AxiosRequestOptions) {
    const cancelRequestKey = this.getCancelRequestKey(config);
    config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
      if (!this.cancel.has(cancelRequestKey)) {
        this.cancel.set(cancelRequestKey , cancel);
      }
    })
  },
  /**
   * 删除取消重复请求的cancelToken
   * @param {AxiosRequestOptions} config 请求配置对象
   */
  removeCancelRequest (config: AxiosRequestOptions) {
    const cancelRequestKey = this.getCancelRequestKey(config);
    if (this.cancel.has(cancelRequestKey)) {
      const cancelToken = this.cancel.get(cancelRequestKey);
      cancelToken(`取消请求：${cancelRequestKey}`);
      this.cancel.delete(cancelRequestKey);
    }
  },
  /**
   * 手动删除重复请求
   * @param key 取消请求的key
   */
  manualCancelRequest (key: string) {
    const cancelToken = this.cancel.get(key);
    cancelToken(`取消请求：${key}`);
    this.cancel.delete(key);
  },
  /**
   * 获取唯一的取消请求的标识，用于取消重复的请求
   * 我们认为是重复的请求，主要是通过请求地址，请求方式，请求参数三个都一样的话，那么我们就认为是重复的请求
   * @param {AxiosRequestOptions} config 请求配置对象 
   */
  getCancelRequestKey (config: AxiosRequestOptions) {
    if (config) {
      const {url , params , method} = config;
      let { data } = config;
      if (typeof data === 'string') {
        data = JSON.parse(data);
      }
      return [url , method , JSON.stringify(data) , JSON.stringify(params)].join('&');
    }
  }
}

function createAxios(axiosConfig: Partial<AxiosRequestOptions>) {
  const defualtOptions: Partial<AxiosRequestOptions> = {
    // 是否取消重复请求，默认取消
    repeatRequestCancel : true,
    // 是否请求成功后保留当前请求的cancelToken，默认为false，不保留，当为true，我们可以通过这个cancelToken，让用户手动删除重复请求
    saveCancelToken : false
  };
  const options = Object.assign({} , defualtOptions , axiosConfig);
  const service = axios.create({
    baseURL: '/',
    timeout: 60000,
    headers: {
      "Content-Type": 'application/json'
    },
    ...options
  });
  service.interceptors.request.use((config: AxiosRequestOptions) => {
    // 删除重复请求
    if (config.repeatRequestCancel) {
      requestCancelUtil.removeCancelRequest(config);
    }
    config.headers['Authorization'] = `Bearer ${Auth.getToken()}`;
    // 需要取消重复请求，那么我们就保存起来
    if (config.repeatRequestCancel) {
      requestCancelUtil.addCancelRequest(config);
    }
    return config;
  }, (error: AxiosError) => {
    return Promise.reject(error);
  });
  service.interceptors.response.use((response: AxiosResponseOptions) => {
    if (response.config.repeatRequestCancel && !response.config.saveCancelToken) {
      requestCancelUtil.removeCancelRequest(response.config);
    }
    return response;
  }, async (error: AxiosError) => {
    if (error.response && error.response!.status === 401) {
      // 如果 401，那么就刷新 token，成功后重新在请求接口
      await Auth.refreshToken();
      error.response.config.headers['Authorization'] = `Bearer ${Auth.getToken()}`;
      return service.request(error.response.config);
    }
    return Promise.reject(error);
  });
  return async function result<T = unknown>(axiosConfig: AxiosRequestConfig , params: Record<string , unknown> = {}): Promise<Result.ResponseResult<T>> {
    const options = Object.assign({} , defualtOptions , axiosConfig , params);
    const { data } = await service<Result.ResponseResult<T>>(options);
    return data;
  };
}
export default createAxios;